﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AdventureWorks.Entities;
using AdventureWorksData.DAO;
using AdventureWorks.Exceptions;
using AdventureWorks.Helpers;

namespace AdventureWorks.Business
{
	public class AddressBusiness : IBusiness<Address>, IDisposable
	{
		private readonly IUnitOfWork _db;
		private IEnumerable<Address> _address;

		public AddressBusiness()
		{
			_db = new UnitOfWork();
		}

		public AddressBusiness(IUnitOfWork entityDb)
		{
			_db = entityDb;
		}

		public Address Format(Address address, int customerID)
		{
			var customer = _db.Customers.Get(customerID);
			address.Customers = new List<Customer>();
			address.Customers.Add(customer);

			if (address.Validate())
			{
				return address;
			}
			ThrowInvalidException();
			return null;
		}

		public IEnumerable<Address> GetList(string sortOrder, string searchString)
		{
			_address = _db.Addresses.Get();
			FilterWithSearchString(searchString);
			SortOrder(sortOrder);

			return _address;
		}

		private void FilterWithSearchString(String searchString)
		{
			if (!String.IsNullOrEmpty(searchString))
			{
				_address = _address.Where(a =>
					CustomComparer.CompareString(
						new String[] { a.ID.ToString(), a.AddressLines, a.City, a.StateProvince, a.CountryRegion, a.PostalCode },
						searchString));
			}
		}

		private void SortOrder(String sortOrder)
		{
			switch (sortOrder)
			{
				case "ID Desc":
					_address = _address.OrderByDescending(p => p.ID);
					break;
				case "AddressLines":
					_address = _address.OrderBy(p => p.AddressLines);
					break;
				case "AddressLines Desc":
					_address = _address.OrderByDescending(p => p.AddressLines);
					break;
				case "City":
					_address = _address.OrderBy(p => p.City);
					break;
				case "City Desc":
					_address = _address.OrderByDescending(p => p.City);
					break;
				case "StateProvince":
					_address = _address.OrderBy(p => p.StateProvince);
					break;
				case "StateProvince Desc":
					_address = _address.OrderByDescending(p => p.StateProvince);
					break;
				case "CountryRegion":
					_address = _address.OrderBy(p => p.CountryRegion);
					break;
				case "CountryRegion Desc":
					_address = _address.OrderByDescending(p => p.CountryRegion);
					break;
				case "Modified":
					_address = _address.OrderBy(p => p.ModifiedDate);
					break;
				case "Modified Desc":
					_address = _address.OrderByDescending(p => p.ModifiedDate);
					break;
				default:
					_address = _address.OrderBy(p => p.ID);
					break;
			}
		}

		public Address Get(int id)
		{
			return _db.Addresses.Get(a => a.ID == id, includeProperties: "Customers").FirstOrDefault();
		}

		public void Insert(Address entity)
		{
			if (entity.Validate())
			{
				_db.Addresses.Insert(entity);
			}
			else
			{
				ThrowInvalidException();
			}
		}

		public void Update(Address entity)
		{
			entity.ModifiedDate = DateTime.Now;
			if (entity.Validate())
			{
				_db.Addresses.Update(entity);
			}
			else
			{
				ThrowInvalidException();
			}
		}

		public void Delete(int id)
		{
			_db.Addresses.Delete(id);
		}

		public void Save()
		{
			_db.Save();
		}

		public void Dispose()
		{
			_db.Dispose();
		}


		public void ThrowInvalidException()
		{
			throw new BusinessException("Invalid Address");
		}
	}
}
